/*++

Copyright (c) 2007  Microsoft Corporation 

Filename: 

    Monitor.cs

Abstract: 

    A class to monitor the machine based on source selected
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.SqlClient;
using System.Management;
using System.Reflection;
using System.Threading;
using System.Globalization;
using Visio = Microsoft.Office.Interop.Visio;
using System.IO;
using System.Collections.ObjectModel;
using Microsoft.EnterpriseManagement;
using Microsoft.EnterpriseManagement.Configuration;
using Microsoft.EnterpriseManagement.Common;
using Microsoft.EnterpriseManagement.Monitoring;

namespace NRTMAddIn
{
    class Monitor
    {
        #region Private Variables

        private Document nrtmDocument;
        private Visio.Window nrtmActiveWindow;
        private Visio.Page nrtmActivePage;

        private AddonWindowWrapper m_statusWindow;

        private StatusDlg statusDlg;

        private Visio.Shape textBoxShape;

        private string ServerMonitorStartMsg    = Global.GetResourceString("ServerMonitorStartMsg_Text");
        private string ServerMonitorCompleteMsg = Global.GetResourceString("ServerMonitorCompleteMsg_Text");
        private string ServerMonitorFailMsg     = Global.GetResourceString("ServerMonitorFailMsg_Text");
        private string ServerMonitorDetailsMsg1 = Global.GetResourceString("ServerMonitorDetailsMsg1_Text");
        private string ServerMonitorDetailsMsg2 = Global.GetResourceString("ServerMonitorDetailsMsg2_Text");

        private WMIServices wmiObject = new WMIServices();

        private int noOfNRTMConfigShapes;
        #endregion

        #region Methods
        /// <summary>
        /// Start disk space monitoring based on the option selected by the user
        /// </summary>
        public void StartDiskMonitoring(object nrtmDoc)
        {
            Global.ThreadStop monitoringFailStatus = Global.ThreadStop.Abort;

            try
            {
                //Invalid document
                if (nrtmDoc == null)
                    return;

                //Store the document reference
                nrtmDocument = (Document)nrtmDoc;
                nrtmActiveWindow = nrtmDocument.VisioDocument.Application.ActiveWindow;
                nrtmActivePage = nrtmDocument.VisioDocument.Application.ActivePage;

                wmiObject.NRTMDocument = nrtmDocument;

                // get the status dialog form
                if (m_statusWindow != null)
                {
                    statusDlg = (StatusDlg)m_statusWindow.FormToShow;
                }
                if (statusDlg != null)
                {
                    // reset the status
                    statusDlg.ResetStatus();

                    // enable the cancel button at the beginning of all new scans
                    statusDlg.CancelButtonEnabled(true);

                    // notify the beginning of the monitoring
                    statusDlg.UpdateStatus(Global.GetResourceString("StatusDlg_Update_Start"));
                }

                //Based on the option start monitoring
                if (nrtmDocument.ipOption == Global.InputDataOption.SCOM)
                {
                    PerformMonitoringUsingSCOMSDK();
                }
                else if (nrtmDocument.ipOption == Global.InputDataOption.ActivePage ||
                    nrtmDocument.ipOption == Global.InputDataOption.ActiveShape ||
                    nrtmDocument.ipOption == Global.InputDataOption.Excel)
                {
                    PerformMonitoringUsingWMI();
                }

                //Monitoring completed with no errors.
                monitoringFailStatus = Global.ThreadStop.Complete;

            }
            catch (NrtmException ex)
            {
                //To catch and display exceptions from sub functions
                NrtmException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                            Global.GetResourceString("Exception_UsrMsg"), ex.InnerException);
            }
            catch (Exception ex)
            {
                //To catch exceptions from current functions
                NrtmException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                            Global.GetResourceString("Exception_UsrMsg"), ex);
            }
            finally
            {
                try
                {
                    //Stop monitoring normally
                    nrtmDocument.StopDiskMonitoring(monitoringFailStatus);
                }
                catch (NrtmException ex)
                {
                    //To catch and display exceptions from sub functions
                    NrtmException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                            Global.GetResourceString("Exception_UsrMsg"), ex.InnerException);
                }
                catch (Exception ex)
                {
                    //To catch exceptions from current functions
                    NrtmException.HandleExceptions(Global.GetResourceString("Exception_MsgBox_Caption"),
                            Global.GetResourceString("Exception_UsrMsg"), ex);
                }
            }
        }

        /// <summary>
        /// Perform disk sapce monitoring using SCOM SDK
        /// </summary>
        public void PerformMonitoringUsingSCOMSDK()
        {
            bool hasNRTM_ConfigProp;
            Visio.Page ActivePage = null;
            string criteriaString = String.Empty;
            string machineString = String.Empty;

            DataRow drMachines = null;

            //Array to store all the shapes
            ArrayList ShapeList = new ArrayList();

            //If no document selected for monitoring end function
            if (nrtmDocument.VisioDocument == null)
            {
                return;
            }

            if (nrtmDocument.MonitorDB.DtMachines.Rows.Count != 0)
            {
                //Clear previous scan data
                nrtmDocument.MonitorDB.DtMachines.Rows.Clear();
            }

            //Save active page to reset at the end
            if (nrtmActivePage != null)
            {
                ActivePage = nrtmActivePage;
            }
            try
            {
                noOfNRTMConfigShapes = 0;
                foreach (Visio.Page currPage in nrtmDocument.VisioDocument.Pages)
                {
                    //Change active page to page being worked on
                    try
                    {
                        nrtmActiveWindow.Page = currPage;
                    }
                    catch (Exception)
                    {
                        //Ignore exception occured due to document closed
                    }
                    AddPageLable(currPage);
                    foreach (Visio.Shape shape in currPage.Shapes)
                    {
                        //Check for server shapes with type = 2
                        if (ConfigureServerShape.ValidNetworkShape(shape))
                        {
                            hasNRTM_ConfigProp = ConfigureServerShape.ShapePropertyExist(shape, "Prop.NRTMConfig");
                            if (hasNRTM_ConfigProp)
                            {
                                string NRTMConfig = shape.get_Cells("Prop.NRTMConfig.Value").get_ResultStr((short)Visio.VisUnitCodes.visNoCast);
                                if (NRTMConfig == "TRUE")
                                {
                                    Visio.Cell cellNtwrkName = shape.get_Cells("Prop.NetworkName.Value");
                                    Visio.Cell cellIpAddress = shape.get_Cells("Prop.IPAddress.Value");
                                    drMachines = nrtmDocument.MonitorDB.DtMachines.NewRow();
                                    drMachines["ServerName"] = cellNtwrkName.FormulaU.Replace("\"", "");
                                    drMachines["IPAddress"] = cellIpAddress.FormulaU.Replace("\"", "");
                                    nrtmDocument.MonitorDB.DtMachines.Rows.Add(drMachines);
                                    ShapeList.Add(shape);
                                    if (String.IsNullOrEmpty(machineString))
                                    {
                                        machineString = String.Format(CultureInfo.InvariantCulture, "Path LIKE '{0}%'", drMachines["ServerName"].ToString());
                                    }
                                    else
                                    {
                                        machineString += " OR " + String.Format(CultureInfo.InvariantCulture, "Path LIKE '{0}%'", drMachines["ServerName"].ToString());
                                    }
                                    //Increment the NRTM configured shapes count
                                    noOfNRTMConfigShapes++;
                                }
                            }
                        }
                    }
                }
                if (noOfNRTMConfigShapes == 0)
                {
                    //No NRTM configured shapes found
                    //Update the status
                    if (statusDlg != null)
                    {
                        statusDlg.UpdateStatus(Global.GetResourceString("StatusDlg_Update_NoShapes"));
                    }
                    return;
                }

                // Get data from SCOM
                criteriaString = String.Format(CultureInfo.InvariantCulture, "FullName LIKE '%{0}%' AND ({1})", Global.GetResourceString("LogicalDisk"), machineString);
                GetDataFromScomSdk(criteriaString);

                //Color all shapes in ShapeList
                ChangeShapesColor(ShapeList);
            }
            catch (System.Threading.ThreadAbortException)
            {
                //Ignore thread abort exception
            }
            catch (NrtmException ex)
            {
                //Exception from sub function. Pass on to entry point
                throw new NrtmException("Perform Monitoring using SCOM SDK", ex.InnerException);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new NrtmException("Perform Monitoring using SCOM SDK", ex);
            }
            finally
            {
                //Reset active page
                if (ActivePage != null)
                {
                    try
                    {
                        nrtmActiveWindow.Page = ActivePage;
                    }
                    catch (Exception)
                    {
                        //Ignore exception occured due to document closed
                    }
                }
            }
        }

        /// <summary>
        /// Get disk space data from SCOM using SDK
        /// </summary>
        /// <param name="criteriaString">Criteria string contains list of machines</param>
        private void GetDataFromScomSdk(string criteriaString)
        {
            ManagementGroup mg = null;

            DataRow drDiskDtails = null;

            bool logiclDiskFlag = true;

            // Define the server that you want to connect to.
            string serverName = Global.ServerName;

            try
            {
                if (nrtmDocument.MonitorDB.DtDiskDetails.Rows.Count != 0)
                {
                    nrtmDocument.MonitorDB.DtDiskDetails.Rows.Clear();
                }

                //Connect to the SCOM SDK service
                mg = ManagementGroup.Connect(serverName);

                if (!mg.IsConnected)
                {
                    return;
                }
                ReadOnlyCollection<MonitoringObject> monitoringObjects_LocalHardware;

                //MonitoringClass monitoringClass_LocalHardware;

                //monitoringClass_LocalHardware = mg.GetMonitoringClass(SystemMonitoringClass.LogicalHardware);
                MonitoringObjectGenericCriteria monitorCriteria = new MonitoringObjectGenericCriteria(criteriaString);
                monitoringObjects_LocalHardware = mg.GetMonitoringObjects(monitorCriteria);

                ReadOnlyCollection<MonitoringClassProperty> properties_LocalHardware;

                foreach (MonitoringObject nextObject_LocalHardware in monitoringObjects_LocalHardware)
                {
                    //Check if the logical hardware is of type logical disk
                    if (nextObject_LocalHardware.FullName.Contains(Global.GetResourceString("LogicalDisk")))
                    {
                        //if health state is initialized then read the data
                        if (nextObject_LocalHardware.HealthState != HealthState.Uninitialized)
                        {
                            logiclDiskFlag = true;
                            drDiskDtails = nrtmDocument.MonitorDB.DtDiskDetails.NewRow();

                            // Get name of the server
                            drDiskDtails["ServerName"] = nextObject_LocalHardware.Path.Substring(0, nextObject_LocalHardware.Path.IndexOf('.'));
                            // Get the display name(drive name) of the drive
                            drDiskDtails["DiskName"] = nextObject_LocalHardware.DisplayName;

                            // Get all monitoring properties
                            properties_LocalHardware = nextObject_LocalHardware.GetMonitoringProperties();

                            foreach (MonitoringClassProperty property in properties_LocalHardware)
                            {
                                if (String.Compare(property.DisplayName, Global.GetResourceString("DriveType"), true, CultureInfo.CurrentCulture) == 0)
                                {
                                    if (System.Int64.Parse(nextObject_LocalHardware.GetMonitoringPropertyValue(property).ToString(), CultureInfo.CurrentCulture) != 3)
                                    {
                                        logiclDiskFlag = false;
                                        break;
                                    }
                                }
                                else if (String.Compare(property.DisplayName, Global.GetResourceString("SizeBytes"), true, CultureInfo.CurrentCulture) == 0)
                                {
                                    drDiskDtails["TotalSizeMB"] = (System.Int64.Parse(nextObject_LocalHardware.GetMonitoringPropertyValue(property).ToString(), CultureInfo.CurrentCulture) / 1048576);
                                }
                                else if (String.Compare(property.DisplayName, Global.GetResourceString("DeviceDescription"), true, CultureInfo.CurrentCulture) == 0)
                                {
                                    drDiskDtails["Description"] = nextObject_LocalHardware.GetMonitoringPropertyValue(property);
                                    if (String.Compare(drDiskDtails["Description"].ToString(), 
                                        Global.GetResourceString("LocalFixedDisk"), true) != 0)
                                    {
                                        logiclDiskFlag = false;
                                        break;
                                    }
                                }
                                else if (String.Compare(property.DisplayName, Global.GetResourceString("FileSystem"), true, CultureInfo.CurrentCulture) == 0)
                                {
                                    drDiskDtails["FileSystem"] = nextObject_LocalHardware.GetMonitoringPropertyValue(property);
                                }
                            }

                            if (!logiclDiskFlag)
                            {
                                drDiskDtails.Delete();
                                continue;
                            }

                            //Get free disk space counter data
                            MonitoringPerformanceDataCriteria perfCriteria = new MonitoringPerformanceDataCriteria(Global.GetResourceString("FreeMbCounter"));

                            ReadOnlyCollection<MonitoringPerformanceData> performanceData =
                                nextObject_LocalHardware.GetMonitoringPerformanceData(perfCriteria);

                            if (performanceData.Count > 0)
                            {
                                MonitoringPerformanceDataValue lastValue = null;
                                DateTime start = DateTime.Today - new TimeSpan(1, 0, 0, 0);

                                ReadOnlyCollection<MonitoringPerformanceDataValue> values = performanceData[0].GetValues(start, DateTime.Now);

                                if (values.Count > 0)
                                {
                                    lastValue = values[values.Count - 1];
                                }
                                else
                                {
                                    lastValue = null;
                                }

                                if (lastValue != null)
                                {
                                    drDiskDtails["FreeSpaceMB"] = lastValue.ToString();
                                    decimal freePerc = (Convert.ToDecimal(drDiskDtails["FreeSpaceMB"].ToString(), CultureInfo.InvariantCulture) /
                                        Convert.ToDecimal(drDiskDtails["TotalSizeMB"].ToString(), CultureInfo.InvariantCulture)) * 100;
                                    drDiskDtails["PerFreeSpace"] = freePerc;
                                    //Disk state based on threshold values
                                    drDiskDtails["DiskState"] = Global.GetDiskState(Convert.ToInt32(freePerc, CultureInfo.InvariantCulture));
                                }
                                else
                                {
                                    //When free space not available do not add row to detail table
                                    drDiskDtails["FreeSpaceMB"] = DBNull.Value;
                                    drDiskDtails["PerFreeSpace"] = DBNull.Value;
                                    drDiskDtails["DiskState"] = Global.GetResourceString("StatusDlg_Update_Unavail");
                                }
                            }

                            //Add row to disk details table
                            nrtmDocument.MonitorDB.DtDiskDetails.Rows.Add(drDiskDtails);
                        }
                    }
                }
            }
            catch (Microsoft.EnterpriseManagement.Common.ServiceNotRunningException ex)
            {
                MessageBox.Show(ex.Message,
                    Global.GetResourceString("Document_MsgBox_Title"),
                    MessageBoxButtons.OK, MessageBoxIcon.Error,
                    MessageBoxDefaultButton.Button1);
            }
            catch (Microsoft.EnterpriseManagement.Common.UnauthorizedAccessMonitoringException ex)
            {
                MessageBox.Show(ex.Message,
                    Global.GetResourceString("Document_MsgBox_Title"),
                    MessageBoxButtons.OK, MessageBoxIcon.Error,
                    MessageBoxDefaultButton.Button1);
            }
            catch (System.Configuration.ConfigurationException)
            {
                MessageBox.Show(Global.GetResourceString("DotNetFrameWork3ErrorMsg"),
                    Global.GetResourceString("Document_MsgBox_Title"),
                    MessageBoxButtons.OK, MessageBoxIcon.Error,
                    MessageBoxDefaultButton.Button1);
            }
            catch (Microsoft.EnterpriseManagement.Common.ServerDisconnectedException)
            {
                MessageBox.Show(String.Format(CultureInfo.InvariantCulture, Global.GetResourceString("AccessErrorMsg"), System.Environment.UserDomainName, System.Environment.UserName),
                    Global.GetResourceString("Document_MsgBox_Title"),
                    MessageBoxButtons.OK, MessageBoxIcon.Error,
                    MessageBoxDefaultButton.Button1);
            }
            catch (System.Threading.ThreadAbortException)
            {
                //Ignore thread abort exception
            }
            catch (NrtmException ex)
            {
                //Exception from sub function. Pass on to entry point
                throw new NrtmException("Get Data From Scom Sdk", ex.InnerException);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new NrtmException("Get Data From Scom Sdk", ex);
            }
        }

        /// <summary>
        /// Perform disk space monitoring using WMI
        /// </summary>
        private void PerformMonitoringUsingWMI()
        {
            ManagementScope RemoteScope = null;
            bool hasNRTM_ConfigProp;
            DataRow drMachines = null;
            Visio.Master DGMaster = null;
            Visio.Page ActivePage = null;
            string errMsg = "";

            //If no document selected for monitoring end function
            if (nrtmDocument.VisioDocument == null)
            {
                return;
            }

            //Clear the disk details & machines tables to start fresh monitoring session
            if (nrtmDocument.MonitorDB.DtDiskDetails.Rows.Count != 0)
            {
                nrtmDocument.MonitorDB.DtDiskDetails.Rows.Clear();
            }
            if (nrtmDocument.MonitorDB.DtMachines.Rows.Count != 0)
            {
                nrtmDocument.MonitorDB.DtMachines.Rows.Clear();
            }

            try
            {
                Global.VisioApp.DeferRecalc = 0;
                Global.VisioApp.ShowChanges = true;
                //Save active page to reset at the end
                if (nrtmActivePage != null)
                {
                    ActivePage = nrtmActivePage;
                }
                noOfNRTMConfigShapes = 0;
                foreach (Visio.Page currPage in nrtmDocument.VisioDocument.Pages)
                {
                    //Change active page to page being worked on
                    try
                    {
                        nrtmActiveWindow.Page = currPage;
                    }
                    catch (Exception)
                    {
                        //Ignore exception occured due to document closed
                    }
                    
                    //Add testbox to display monitoring start time
                    AddPageLable(currPage);

                    foreach (Visio.Shape shape in currPage.Shapes)
                    {
                        //Check for server shapes with type = 2 i.e Server & master name
                        if (ConfigureServerShape.ValidNetworkShape(shape))
                        {
                            hasNRTM_ConfigProp = ConfigureServerShape.ShapePropertyExist(shape, "Prop.NRTMConfig");
                            if (hasNRTM_ConfigProp)
                            {
                                string NRTMConfig = shape.get_Cells("Prop.NRTMConfig.Value").get_ResultStr((short)Visio.VisUnitCodes.visNoCast);
                                if (NRTMConfig == "TRUE")
                                {
                                    string cellNtwrkName = shape.get_Cells("Prop.NetworkName.Value").FormulaU.Replace("\"", "").ToUpper(CultureInfo.CurrentCulture);
                                    string cellIpAddress = shape.get_Cells("Prop.IPAddress.Value").FormulaU.Replace("\"", "").ToUpper(CultureInfo.CurrentCulture);

                                    string host = "";
                                    //If server name is empty use ip address
                                    if (string.IsNullOrEmpty(cellNtwrkName))
                                        host = cellIpAddress;
                                    else
                                        host = cellNtwrkName;

                                    RemoteScope = WMIServices.GetWMIScope(host, ref errMsg);
                                    if (RemoteScope != null)
                                    {
                                        //If ip address is empty fetch from database
                                        //if (string.IsNullOrEmpty(cellIpAddress))
                                        //{
                                        cellIpAddress = WMIServices.GetNetworkAddresses(RemoteScope);
                                        shape.get_Cells("Prop.IPAddress.Value").FormulaU = "\"" + cellIpAddress + "\"";
                                        //}
                                        //If server name is empty use ip address
                                        if (string.IsNullOrEmpty(cellNtwrkName)
                                            || String.Compare(cellNtwrkName, Global.GetResourceString("LocalHost"), true, CultureInfo.CurrentCulture) == 0)
                                        {
                                            cellNtwrkName = WMIServices.GetServerName(RemoteScope);
                                            shape.get_Cells("Prop.NetworkName.Value").FormulaU = "\"" + cellNtwrkName + "\"";
                                        }

                                        //Update the status
                                        if (statusDlg != null)
                                        {
                                            statusDlg.UpdateStatus(string.Empty);
                                            statusDlg.UpdateStatus(string.Format(CultureInfo.InvariantCulture, ServerMonitorStartMsg, cellNtwrkName));
                                        }

                                        //Machine details available
                                        if (!wmiObject.GetLogicalDrives(RemoteScope, cellNtwrkName))
                                        {
                                            AddNullRow(cellNtwrkName, Global.GetResourceString("StatusDlg_Update_Unavail"));
                                        }
                                    }
                                    else
                                    {
                                        errMsg = errMsg.Remove(errMsg.IndexOf('.') + 1);

                                        //Add a row with null data into disk details table
                                        AddNullRow(host, errMsg);

                                        //Invalid server name or ip address
                                        //Update the status
                                        if (statusDlg != null)
                                        {
                                            statusDlg.UpdateStatus(string.Empty);
                                            statusDlg.UpdateStatus(string.Format(CultureInfo.InvariantCulture, ServerMonitorStartMsg, host));
                                            statusDlg.UpdateStatus(string.Format(CultureInfo.InvariantCulture, ServerMonitorFailMsg, host, errMsg));
                                        }
                                    }

                                    //Store server name and ipaddress in machine table used in report generation
                                    drMachines = nrtmDocument.MonitorDB.DtMachines.NewRow();
                                    drMachines["ServerName"] = cellNtwrkName;
                                    drMachines["IPAddress"] = cellIpAddress;
                                    nrtmDocument.MonitorDB.DtMachines.Rows.Add(drMachines);

                                    if (DGMaster == null)
                                    {
                                        //Add data graphics from DG file
                                        ApplyDataGraphics(shape);
                                        DGMaster = shape.DataGraphic;
                                    }
                                    else
                                    {
                                        //Add data graphics from previous shape
                                        shape.DataGraphic = DGMaster;
                                    }

                                    //Update the server color based on the available disk space
                                    ChangeShapeColor(shape);

                                    //Increment the NRTM configured shapes count
                                    noOfNRTMConfigShapes++;
                                }
                            }
                        }
                    }
                }
                if (noOfNRTMConfigShapes == 0)
                {
                    //No NRTM configured shapes found
                    //Update the status
                    if (statusDlg != null)
                    {
                        statusDlg.UpdateStatus(string.Empty);
                        statusDlg.UpdateStatus(Global.GetResourceString("StatusDlg_Update_NoShapes"));
                    }
                    return;
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                //Ignore thread abort exception
            }
            catch (NrtmException ex)
            {
                //Exception from sub function. Pass on to entry point
                throw new NrtmException("Stop Monitoring", ex.InnerException);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new NrtmException("Stop Monitoring", ex);
            }
            finally
            {
                Global.VisioApp.ShowChanges = true;
                Global.VisioApp.DeferRecalc = 0;
                //Reset active page
                if (ActivePage != null)
                {
                    try
                    {
                        nrtmActiveWindow.Page = ActivePage;
                    }
                    catch (Exception)
                    {
                        //Ignore exception occured due to document closed
                    }
                }
            }

        }

        /// <summary>
        /// Add a row with null values to disk details table
        /// </summary>
        /// <param name="serverName">Server Name</param>
        /// <param name="state">Disk State</param>
        private void AddNullRow(string serverName, string state)
        {
            DataRow drDiskDtails = null;
            try
            {
                drDiskDtails = nrtmDocument.MonitorDB.DtDiskDetails.NewRow();
                drDiskDtails["ServerName"] = serverName;
                drDiskDtails["DiskName"] = DBNull.Value;
                drDiskDtails["TotalSizeMB"] = DBNull.Value;
                drDiskDtails["FreeSpaceMB"] = DBNull.Value;
                drDiskDtails["FileSystem"] = DBNull.Value;
                drDiskDtails["Description"] = DBNull.Value;
                drDiskDtails["PerFreeSpace"] = DBNull.Value;
                drDiskDtails["DiskState"] = state;
                nrtmDocument.MonitorDB.DtDiskDetails.Rows.Add(drDiskDtails);
            }
            catch (System.Threading.ThreadAbortException)
            {
                //Ignore thread abort exception
            }
            catch (NrtmException ex)
            {
                //Exception from sub function. Pass on to entry point
                throw new NrtmException("Add Null Row", ex.InnerException);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new NrtmException("Add Null Row", ex);
            }
        }

        /// <summary>
        /// Change color of entire array of shapes
        /// </summary>
        /// <param name="ServerShapes">Array of shapes to color</param>
        private void ChangeShapesColor(ArrayList ServerShapes)
        {
            Visio.Master DGMaster = null;
            string server = "";

            try
            {
                Global.VisioApp.DeferRecalc = 0;
                Global.VisioApp.ShowChanges = true;
                foreach (Visio.Shape shape in ServerShapes)
                {
                    server = shape.get_Cells("Prop.NetworkName.Value").FormulaU;
                    server = server.Replace("\"", "");

                    //Update the status
                    if (statusDlg != null)
                    {
                        statusDlg.UpdateStatus(string.Empty);
                        statusDlg.UpdateStatus(string.Format(CultureInfo.InvariantCulture,ServerMonitorStartMsg, server));
                    }

                    if (DGMaster == null)
                    {
                        //Add data graphics from DG file
                        ApplyDataGraphics(shape);
                        DGMaster = shape.DataGraphic;
                    }
                    else
                    {
                        //Add data graphics from previous shape
                        shape.DataGraphic = DGMaster;
                    }

                    if (!ChangeShapeColor(shape))
                    {
                        //Update the failed status
                        if (statusDlg != null)
                        {
                            statusDlg.UpdateStatus(string.Format(CultureInfo.InvariantCulture,ServerMonitorFailMsg, server, Global.GetResourceString("StatusDlg_Update_Unavail")));
                        }
                    }
                }
            }
            catch (System.Threading.ThreadAbortException)
            {
                //Ignore thread abort exception
            }
            catch (NrtmException ex)
            {
                //Exception from sub function. Pass on to entry point
                throw new NrtmException("Color Shapes", ex.InnerException);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new NrtmException("Color Shapes", ex);
            }
        }

        /// <summary>
        /// Change color of a single shape
        /// </summary>
        /// <param name="shape">Shape to change the color</param>
        /// <returns></returns>
        private bool ChangeShapeColor(Visio.Shape shape)
        {
            int freePerc = 0;
            DataTable dtDiskDetails = nrtmDocument.MonitorDB.DtDiskDetails;
            DataRow[] drDiskDtails = null;
            string serverName = string.Empty;
            string serverText = string.Empty;
            string ipaddress = string.Empty;
            string diskState = string.Empty;
            try
            {
                ipaddress = shape.get_Cells("Prop.IPAddress.Value").FormulaU.Replace("\"", "");
                serverName = shape.get_Cells("Prop.NetworkName.Value").FormulaU;
                serverName = serverName.Replace("\"", "");
                string filter = "ServerName = '" + serverName + "'";

                //Set shape text equal to machine name
                //Max 10 characters displayed in text
                serverText = serverName;
                if (serverText.Length > 10)
                    serverText = serverText.Substring(0, 10) + "..";
                shape.Text = serverText;
                Visio.Characters vsoChars = shape.Characters;
                vsoChars.Begin = 0;
                vsoChars.set_CharProps(7, 6);

                if (string.IsNullOrEmpty(serverName))
                {
                    //Machine details not available
                    shape.get_CellsU("User.NRTMStatus").set_ResultFromInt(
                        (short)Visio.VisUnitCodes.visNoCast,
                         Convert.ToInt32(Convert.ToInt32(Global.VisioColors.Black, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture));
                    shape.get_CellsU("Actions.DrillAction.Disabled").FormulaU = "\"1\"";
                    return false;
                }

                freePerc = 0;

                //Get the disk details with least free space
                drDiskDtails = dtDiskDetails.Select(filter, "PerFreeSpace ASC");

                if (drDiskDtails.Length == 0)
                {
                    //Machine details not available
                    shape.get_CellsU("User.NRTMStatus").set_ResultFromInt(
                        (short)Visio.VisUnitCodes.visNoCast,
                         Convert.ToInt32(Convert.ToInt32(Global.VisioColors.Black, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture));
                    shape.get_CellsU("Actions.DrillAction.Disabled").FormulaU = "\"1\"";
                    AddNullRow(serverName, Global.GetResourceString("StatusDlg_Update_Unavail"));
                    return false;
                }
                if (drDiskDtails[0].ItemArray[6] != DBNull.Value)
                {
                    freePerc = (int)drDiskDtails[0].ItemArray[6];
                }
                else
                {
                    //Free Space details not availble
                    shape.get_CellsU("User.NRTMStatus").set_ResultFromInt(
                        (short)Visio.VisUnitCodes.visNoCast,
                         Convert.ToInt32(Convert.ToInt32(Global.VisioColors.Black, CultureInfo.InvariantCulture), CultureInfo.InvariantCulture));
                    shape.get_CellsU("Actions.DrillAction.Disabled").FormulaU = "\"1\"";
                    return false;
                }

                //Get disk state based on free space
                diskState = Global.GetDiskState(freePerc);

                //Set the color based on the disk state
                if (string.Compare(diskState, Global.GetResourceString("DiskState_Healthy")) == 0)
                {
                    shape.get_CellsU("User.NRTMStatus").set_ResultFromInt(
                        (short)Visio.VisUnitCodes.visNoCast,
                         Convert.ToInt32(Convert.ToInt32(Global.VisioColors.Green, CultureInfo.InvariantCulture)));
                }
                else if (string.Compare(diskState, Global.GetResourceString("DiskState_Normal")) == 0)
                {
                    shape.get_CellsU("User.NRTMStatus").set_ResultFromInt(
                        (short)Visio.VisUnitCodes.visNoCast,
                         Convert.ToInt32(Global.VisioColors.Yellow, CultureInfo.InvariantCulture));
                }
                else if (string.Compare(diskState, Global.GetResourceString("DiskState_Low")) == 0)
                {
                    shape.get_CellsU("User.NRTMStatus").set_ResultFromInt(
                        (short)Visio.VisUnitCodes.visNoCast,
                        Convert.ToInt32(Global.VisioColors.Red, CultureInfo.InvariantCulture));
                }

                //Enable view details
                shape.get_CellsU("Actions.DrillAction.Disabled").FormulaU = "\"0\"";

                //Update the status of the machine
                if (statusDlg != null)
                {
                    statusDlg.UpdateStatus(string.Format(CultureInfo.InvariantCulture,ServerMonitorCompleteMsg, serverName));
                    statusDlg.UpdateStatus(string.Empty);
                    statusDlg.UpdateStatus(ServerMonitorDetailsMsg1);
                    statusDlg.UpdateStatus(string.Format(CultureInfo.InvariantCulture,ServerMonitorDetailsMsg2, serverName, ipaddress, diskState));
                }
                return true;
            }
            catch (System.Threading.ThreadAbortException)
            {
                //Ignore thread abort exception
                return true;
            }
            catch (NrtmException ex)
            {
                //Exception from sub function. Pass on to entry point
                throw new NrtmException("Color Shape", ex.InnerException);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new NrtmException("Color Shape", ex);
            }
            finally
            {
                System.Windows.Forms.Application.DoEvents();
            }
        }

        /// <summary>
        /// Gets or sets the status window.
        /// </summary>
        internal AddonWindowWrapper StatusWindow
        {
            set { m_statusWindow = value; }
        }

        /// <summary>
        /// Add text label to Visio page
        /// </summary>
        /// <param name="currPage"></param>
        private void AddPageLable(Visio.Page currPage)
        {
            try
            {
                //Get the page label on current page
                textBoxShape = currPage.Shapes["NRTMPageLabel"];
            }
            catch (System.Runtime.InteropServices.COMException)
            {
                double pageWidth = 0;
                double pageHeight = 0;

                // Get page width
                pageWidth = currPage.PageSheet.get_Cells("PageWidth").ResultIU;

                // Get page height
                pageHeight = currPage.PageSheet.get_Cells("PageHeight").ResultIU;

                //If doesnt exist create new
                textBoxShape = currPage.DrawRectangle(2.5, 8, 8.3, 8);

                // Set shape position to top-center of the page
                textBoxShape.SetCenter(pageWidth / 2, pageHeight - 0.5);
            }           
            textBoxShape.Text = Global.GetResourceString("VisioPageLabel_Text")+ DateTime.Now;
            textBoxShape.TextStyle = "Normal";
            textBoxShape.LineStyle = "Text Only";
            textBoxShape.FillStyle = "Text Only";
            textBoxShape.Name = "NRTMPageLabel";
        }

        /// <summary>
        /// Apply data graphics from stencil
        /// </summary>
        /// <param name="shape">Shape to apply data graphics on</param>
        private static void ApplyDataGraphics(Visio.Shape shape)
        {
            Visio.Master DGMaster = null;

            try
            {
                DGMaster = Global.VisioApp.Documents[Global.AddinStencil].Masters.get_ItemU("NRTM_DG");

                //Add data graphics
                shape.DataGraphic = DGMaster;
            }
            catch (System.Threading.ThreadAbortException)
            {
                //Ignore thread abort exception
            }
            catch (NrtmException ex)
            {
                //Exception from sub function. Pass on to entry point
                throw new NrtmException("Apply data graphics", ex.InnerException);
            }
            catch (Exception ex)
            {
                //Exception from current function
                throw new NrtmException("Apply data graphics", ex);
            }
        }
        #endregion
    }
}
